﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using RSALicCore;

namespace RSALicUI
{
    public partial class QRParseCtrl : UserControl, IQRParser
    {
        public QRParseCtrl()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            rect = new Rectangle(0, 0, this.Width - 1, this.Height - 1);

            oriWidth = this.Width;
            oriHeight = this.Height;

            TryGetData();
        }


        /// <summary>
        /// 获取用户选择的区域的图片
        /// 改方法获取的图片为原始图片的分辨率
        /// 图片比较大
        /// 会导致二维码识别失败
        /// </summary>
        /// <returns></returns>
        Image GetSelectAreaImage()
        {
            if (this.BackgroundImage == null)
            {
                return null;
            }

            if (rect.Width < 10 || rect.Height < 10)
            {
                rect = new Rectangle(0, 0, this.Width, this.Height);
            }
            int dx = 0, dy = 0;
            float sx = 0, sy = 0;
            var imgW = this.BackgroundImage.Width;
            var imgH = this.BackgroundImage.Height;
            CalcDxDy(
                new Point(this.oriWidth, this.oriHeight), 
                new Point(imgW, imgH), 
                ref dx, ref dy, ref sx, ref sy);

            var realRc = new Rectangle(
                (int)((rect.X - dx) * sx),
                (int)((rect.Y - dy) * sy),
                (int)(rect.Width * sx),
                (int)(rect.Height * sy));

            var img = this.BackgroundImage.CutRectangle(realRc);
            var imgsize = Math.Max(img.Width, img.Height);
            if (imgsize > 400)
            {
                var ssx = 400.0 / img.Width;
                var ssy = 400.0 / img.Height;
                if (ssx > ssy)
                {
                    ssy = ssx;
                }
                else
                {
                    ssx = ssy;
                }

                var thbn = img.GetThumbnailImage((int)(img.Width * ssx), (int)(img.Height * ssy), () => false, IntPtr.Zero);
                img.Dispose();
                img = thbn;
            }
            // img.Save("F:\\Test.png");
            return img;
        }

        /// <summary>
        /// 获取到解析图片事件
        /// </summary>
        public event Action<Image> ParseImageGeted;


        Point begin;
        Rectangle rect;
        bool drawing = false;
        Pen rectPen = new Pen(Color.Red);

        private void QRCodeParseCtrl_MouseDown(object sender, MouseEventArgs e)
        {
            begin = e.Location;
            drawing = true;
        }

        int oriWidth = 0;
        int oriHeight = 0;

        public event Action DrawRectFinished;

        public event Action<string> QrDetected;

        void TryGetData()
        {
            GetQrData();
        }

        private void QRCodeParseCtrl_MouseUp(object sender, MouseEventArgs e)
        {
            if (moved)
            {
                TryGetData();
                DrawRectFinished?.Invoke();
            }
            drawing = false;
            oriWidth = this.Width;
            oriHeight = this.Height;
            moved = false;
        }

        bool moved = false;

        private void QRCodeParseCtrl_MouseMove(object sender, MouseEventArgs e)
        {
            if (drawing)
            {
                moved = true;
                var end = e.Location;
                rect.X = Math.Min(begin.X, end.X);
                rect.Y = Math.Min(begin.Y, end.Y);
                rect.Width = Math.Abs(begin.X - end.X);
                rect.Height = Math.Abs(begin.Y - end.Y);
                Invalidate();
            }
        }


        private void QRCodeParseCtrl_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawRectangle(rectPen, rect);
        }

        /// <summary>
        /// 计算内部矩形Zoom到外部矩形的坐标偏移和缩放比例
        /// </summary>
        /// <param name="rcOut">外部矩形</param>
        /// <param name="rcIn">内部矩形</param>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <param name="sx"></param>
        /// <param name="sy"></param>
        void CalcDxDy(Point rcOut, Point rcIn, ref int dx, ref int dy, ref float sx, ref float sy)
        {
            dx = (rcIn.X - rcOut.X) / 2;
            dy = (rcIn.Y - rcOut.Y) / 2;
            sx = rcIn.X * 1.0f / rcOut.X;
            sy = rcIn.Y * 1.0f / rcOut.Y;
            if (sx > sy)
            {
                dx = 0;
                dy = Math.Abs(rcOut.Y - (int)(rcIn.Y / sx)) / 2;
                sy = sx;
            }
            else
            {
                dx = Math.Abs(rcOut.X - (int)(rcIn.X / sy)) / 2;
                dy = 0;
                sx = sy;
            }
        }

        void ProcResize()
        {
            if (this.BackgroundImage == null)
            {
                return;
            }
            var w = this.Width;
            var h = this.Height;

            int dx = 0, dy = 0;
            float sx = 0, sy = 0;
            var imgW = this.BackgroundImage.Width;
            var imgH = this.BackgroundImage.Height;
            var imgRc = new Point(imgW, imgH);
            CalcDxDy(new Point(this.oriWidth, this.oriHeight), imgRc, ref dx, ref dy, ref sx, ref sy);

            var realRc = new RectangleF(
               (rect.X - dx) * sx,
               (rect.Y - dy) * sy,
               rect.Width * sx,
               rect.Height * sy);

            var realRcPct = new RectangleF(
                realRc.X * 1.0f / imgW,
                realRc.Y * 1.0f / imgH,
                realRc.Width * 1.0f / imgW,
                realRc.Height * 1.0f / imgH);

            CalcDxDy(new Point(this.Width, this.Height), imgRc, ref dx, ref dy, ref sx, ref sy);

            realRc.X = dx;
            realRc.Y = dy;
            realRc.Width = this.Width - dx * 2;
            realRc.Height = this.Height - dy * 2;

            rect.X = dx + (int)(realRc.Width * realRcPct.X + 0.5);
            rect.Y = dy + (int)(realRc.Height * realRcPct.Y + 0.5);
            rect.Width = (int)(realRc.Width * realRcPct.Width + 0.5);
            rect.Height = (int)(realRc.Height * realRcPct.Height + 0.5);

            this.oriWidth = this.Width;
            this.oriHeight = this.Height;

            TryGetData();
            Invalidate();
        }

        private void QRCodeParseCtrl_Resize(object sender, EventArgs e)
        {
            ProcResize();
        }

        private void QRCodeParseCtrl_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            using (var dlg = new OpenFileDialog())
            {
                dlg.Title = "选择二维码图片";
                dlg.Filter = "二维码图片|*.jpg;*.png;*.bmp";
                var res = dlg.ShowDialog();
                if (res == DialogResult.OK)
                {
                    var file = dlg.FileName;
                    var bmp = new Bitmap(file);
                    SetData(bmp);
                }
            }
        }

        public void SetData(Image qrImg)
        {
            this.BackgroundImage = qrImg;
            rect = new Rectangle(0, 0, Width, Height);
            TryGetData();
            Invalidate();
        }

        public string GetQrData()
        {
            var img = GetSelectAreaImage();
            if (img == null)
            {
                return null;
            }
            ParseImageGeted?.Invoke(img);
            var qrdata =  QRCodeHelper.Parse(img);
            QrDetected?.Invoke(qrdata);
            return qrdata;
        }
    }
}
